/*
 * Copyright 2009 BioTeam Inc
 * 
 * Licensed under License GNU LESSER GENERAL PUBLIC LICENSE version 3.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.gnu.org/copyleft/lesser.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.bioteam.appweb.model;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

public class XmlToProgram {
	public static String XML_DIRECTORY = "d:\\bio\\Xml";

	/**
	 * 
	 * @param commandName:
	 *            program name such as blastall, etc.
	 * @return a Program instance representing the program.
	 * 
	 * @throws FileNotFoundException
	 * @throws BadProgramSpecException
	 */
	public synchronized static Program toProgram(String commandName)
			throws FileNotFoundException, BadProgramSpecException {
		File file = new File(XML_DIRECTORY + File.separator + commandName
				+ ".xml");
		long lastmodified = 0;

		if (!file.exists()) {
			return null;
		}
		lastmodified = file.lastModified();

		InputStream in = null;

		try {
			in = new FileInputStream(file);
		} catch (FileNotFoundException e) {
			// ignore since file is checked before this call.
		}

		try {
			Program prog = constructProgram(in, commandName);
			prog.setLastmodified(lastmodified);
			prog.setAcd(false);
			prog.setFile(file.getAbsolutePath());

			return prog;
		} catch (JAXBException e) {
			throw new BadProgramSpecException("JAXB failed for " + commandName,
					e);
		} catch (TransformerException e) {
			throw new BadProgramSpecException("XSLT transform failed for "
					+ commandName, e);
		}
	}

	public static Program constructProgram(InputStream in, String commandName)
			throws JAXBException, TransformerException {
		TransformerFactory tf = TransformerFactory.newInstance();

		// original xml file
		StreamSource ss = new StreamSource(in);

		// internal xsl file.
		InputStream sin = Thread.currentThread().getContextClassLoader()
				.getResourceAsStream("net/bioteam/appweb/model/program.xslt");
		StreamSource xsls = new StreamSource(sin);

		StringWriter buffer = new StringWriter();
		StreamResult sr = new StreamResult(buffer);

		Transformer transformer = tf.newTransformer(xsls);
		transformer.transform(ss, sr);

		JAXBContext jc = JAXBContext.newInstance("net.bioteam.appweb.model");
		Unmarshaller unmarshaller = jc.createUnmarshaller();
		unmarshaller.setProperty("com.sun.xml.bind.ObjectFactory",new ObjectFactory());
		Object obj = unmarshaller
				.unmarshal(new StringReader(buffer.toString()));
		JAXBElement<Program> jcmd = (JAXBElement<Program>) obj;
		Program cmd = (Program) jcmd.getValue();
		return cmd;
	}
}
